www.gusucode.com > VC++ SkinCtrls窗体常用控件换肤程序-源码程序 > VC++ SkinCtrls窗体常用控件换肤程序-源码程序/code/Shared/RoundCorner.cpp

    // Roundcnr.cpp: implementation of the CRoundCorner class.
// Download by http://www.NewXing.com
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Roundcorner.h"
#include "syscolors.h"

#include <math.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

const double Pi = 3.141592654;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

enum { COLD, DOWN , HOT };

struct Corner
{
	Corner() { bInfillBetween = FALSE; }

	CPoint ptQuadrant;
	CPoint ptOriginOffset;
	COLORREF crFrom, crTo;
	int nAngleFrom, nAngleTo;
	BOOL bInfillBetween;
};

// precalculated color factors
float fHiliteFactor[] = { 0.2f, 0.35f, 0.29f, 0.24f, 0.18f, 0.12f, 0.06f };
float fShadowFactor[] = { 0.7f, 0.75f, 0.81f, 0.85f, 0.88f, 0.91f, 0.95f };

const int NUMFACTORS = sizeof(fHiliteFactor) / sizeof(float);

//////////////////////////////////////////////////////////////////////

CRoundCorner::CRoundCorner(CWnd* pWnd, int nRadius, COLORREF crBkgnd)
{
	ASSERT (pWnd);
	m_pWnd = pWnd;
	m_nRadius = max(0, nRadius);
	m_crBkgnd = crBkgnd;
}

CRoundCorner::~CRoundCorner()
{

}

void CRoundCorner::Draw(int nCorners, DWORD dwStyle)
{
	ASSERT (m_pWnd);
	
	if (!m_pWnd)
		return;

	CRect rWnd;
	m_pWnd->GetWindowRect(rWnd);

	CWindowDC dc(m_pWnd);

	Draw(&dc, rWnd, m_nRadius, nCorners, dwStyle, m_crBkgnd);
}

// static version
void CRoundCorner::Draw(CDC* pDC, LPRECT pRect, int nRadius, int nCorners, DWORD dwStyle, COLORREF crBkgnd)
{
	// special case: if cold and the backgnd color 
	// has not been specified then nothing to draw
	int nState = (dwStyle & RC_DOWN) ? DOWN : (dwStyle & RC_UP) ? HOT : COLD;

	if (nState == COLD && crBkgnd == -1)
		return;

	// edge style
	if (dwStyle & RC_RENDER)
	{
		ASSERT (dwStyle & RC_EDGES);

		if (!(dwStyle & RC_EDGES))
			return;

		if (crBkgnd == (COLORREF)-1)
			crBkgnd = GetColor(COLOR_3DFACE, -1);
	}

	CRect rect(pRect);

//	BOOL bDefBtn = (dwStyle & RC_DEFBTN) && (dwStyle & RC_EDGES); 
	
//	if (bDefBtn)
//		rect.DeflateRect(1, 1);

	rect.right--;
	rect.bottom--;

	nRadius = max(0, nRadius);

	// the maximum allowable radius depends one which Corners are to drawn
	int nMaxRadius = 0;
	BOOL bTopLeft = (nCorners & RC_TOPLEFT);
	BOOL bTopRight = (nCorners & RC_TOPRIGHT);
	BOOL bBottomLeft = (nCorners & RC_BOTTOMLEFT);
	BOOL bBottomRight = (nCorners & RC_BOTTOMRIGHT);

	if (bTopLeft && bTopRight && !bBottomLeft && !bBottomRight)
		nMaxRadius = min(rect.Height(), rect.Width() / 2);

	else if (!bTopLeft && !bTopRight && bBottomLeft && bBottomRight)
		nMaxRadius = min(rect.Height(), rect.Width() / 2); // same

	else if (bTopLeft && bBottomLeft && !bTopRight && !bBottomRight)
		nMaxRadius = min(rect.Width(), rect.Height() / 2);

	else if (!bTopLeft && !bBottomLeft && bTopRight && bBottomRight)
		nMaxRadius = min(rect.Width(), rect.Height() / 2); // same

	else 
		nMaxRadius = min(rect.Width(), rect.Height()) / 2;

	nRadius = min(nRadius, nMaxRadius);

	if (nRadius)
	{
		// draw the Corners first and then the connecting edges
		if (bTopLeft)
			DrawTopLeft(pDC, rect, nRadius, dwStyle, crBkgnd);

		if (bTopRight)
			DrawTopRight(pDC, rect, nRadius, dwStyle, crBkgnd);

		if (bBottomRight)
			DrawBottomRight(pDC, rect, nRadius, dwStyle, crBkgnd);

		if (bBottomLeft)
			DrawBottomLeft(pDC, rect, nRadius, dwStyle, crBkgnd);
	}

	// now the edges
	DrawEdges(pDC, rect, nRadius, nCorners, dwStyle, crBkgnd);

	// now the def button border
/*	if (bDefBtn)
	{
		rect.InflateRect(1, 1);
		DrawDefBtnBorder(pDC, rect, nRadius, nCorners);
	}
*/
}

void CRoundCorner::DrawDefBtnBorder(CDC* pDC, LPRECT pRect, int nRadius, int nCorners)
{
	if (!nRadius || !nCorners)
	{
		pDC->Draw3dRect(pRect, 0, 0);
		return;
	}

	BOOL bTopLeft = (nCorners & RC_TOPLEFT);
	BOOL bTopRight = (nCorners & RC_TOPRIGHT);
	BOOL bBottomLeft = (nCorners & RC_BOTTOMLEFT);
	BOOL bBottomRight = (nCorners & RC_BOTTOMRIGHT);

	Corner cnr;
	CRect rect(pRect);
	nRadius = max(0, nRadius);
	nRadius = min(nRadius, min(rect.Width(), rect.Height()) / 2);

	cnr.crFrom = cnr.crTo = 0;
	cnr.bInfillBetween = TRUE;

	// top left
	if (bTopLeft)
	{
		cnr.ptQuadrant = CPoint(-1, 1);
		cnr.ptOriginOffset = CPoint(rect.left + nRadius, rect.top + nRadius);
		cnr.nAngleFrom = 270;
		cnr.nAngleTo = 360;

		DrawCorner(pDC, nRadius, &cnr);
	}

	// top right
	if (bTopRight)
	{
		cnr.ptQuadrant = CPoint(1, 1);
		cnr.ptOriginOffset = CPoint(rect.right - nRadius, rect.top + nRadius);
		cnr.nAngleFrom = 0;
		cnr.nAngleTo = 90;

		DrawCorner(pDC, nRadius, &cnr);
	}

	// bottom left
	if (bBottomLeft)
	{
		cnr.ptQuadrant = CPoint(-1, -1);
		cnr.ptOriginOffset = CPoint(rect.left + nRadius, rect.bottom - nRadius);
		cnr.nAngleFrom = 180;
		cnr.nAngleTo = 270;

		DrawCorner(pDC, nRadius, &cnr);
	}

	// bottom right
	if (bBottomRight)
	{
		cnr.ptQuadrant = CPoint(1, -1);
		cnr.ptOriginOffset = CPoint(rect.right - nRadius, rect.bottom - nRadius);
		cnr.nAngleFrom = 90;
		cnr.nAngleTo = 180;

		DrawCorner(pDC, nRadius, &cnr);
	}

	// edges

	// top
	CRect rHLine(rect.left + (bTopLeft ? nRadius : 0), rect.top, 
				rect.right - (bTopRight ? nRadius: 0), rect.top + 1);

	// left
	CRect rVLine(rect.left, rect.top + (bTopLeft ? nRadius : 0), 
				rect.left + 1, rect.bottom - (bBottomLeft ? nRadius : 0));

	pDC->FillSolidRect(rHLine, 0);
	pDC->FillSolidRect(rVLine, 0);
	
	// bottom
	rHLine.SetRect(rect.left + (bBottomLeft ? nRadius : 0), rect.bottom, 
					rect.right - ((bBottomRight && nRadius) ? nRadius : -1), rect.bottom + 1);
	
	// right
	rVLine.SetRect(rect.right, rect.top + (bTopRight ? nRadius : 0), 
					rect.right + 1, rect.bottom - ((bBottomRight && nRadius) ? nRadius : -1));

	pDC->FillSolidRect(rHLine, 0);
	pDC->FillSolidRect(rVLine, 0);
}

void CRoundCorner::DrawEdges(CDC* pDC, LPRECT pRect, int nRadius, int nCorners, DWORD dwStyle, COLORREF crBkgnd)
{
	if (!(dwStyle & RC_EDGES)) // sanity check
		return;

	BOOL bRender = (dwStyle & RC_RENDER);
	BOOL bThin = !bRender && (dwStyle & RC_THIN);

	int nState = (dwStyle & RC_DOWN) ? DOWN : (dwStyle & RC_UP) ? HOT : COLD;

	// if cold and the backgnd color has not been set then nothing to draw
	if (nState == COLD && crBkgnd == -1)
		return;

	BOOL bTopLeft = (nCorners & RC_TOPLEFT);
	BOOL bTopRight = (nCorners & RC_TOPRIGHT);
	BOOL bBottomLeft = (nCorners & RC_BOTTOMLEFT);
	BOOL bBottomRight = (nCorners & RC_BOTTOMRIGHT);

	CRect rect(pRect);
	COLORREF color;

	nRadius = max(0, nRadius);
	nRadius = min(nRadius, min(rect.Width(), rect.Height()) / 2);

	// top
	CRect rHLine(rect.left + (bTopLeft ? nRadius : 0), rect.top, 
				rect.right - (bTopRight ? nRadius: 0), rect.top + 1);

	// left
	CRect rVLine(rect.left, rect.top + (bTopLeft ? nRadius : 0), 
				rect.left + 1, rect.bottom - (bBottomLeft ? nRadius : 0));

	if (bRender && crBkgnd != -1)
	{
		int nLine = 0;
		int nMaxLine = nRadius ? min(NUMFACTORS, nRadius) : 
								min(NUMFACTORS, min(rect.Width(), rect.Height()) / 2);

		do
		{
			int nFactor = (nLine * NUMFACTORS) / nMaxLine;

			COLORREF color = (nState == DOWN) ? Darker(crBkgnd, fShadowFactor[nFactor]) : 
							(nState == HOT) ? Lighter(crBkgnd, fHiliteFactor[nFactor]) : crBkgnd;

			pDC->FillSolidRect(rHLine, color);
			pDC->FillSolidRect(rVLine, color);
			rHLine.OffsetRect(0, 1);
			rVLine.OffsetRect(1, 0);

			if (!nRadius)
			{
				// shorten by one pixel
				rHLine.DeflateRect(1, 0);
				rVLine.DeflateRect(0, 1);
			}

			nLine++;
		}
		while (nLine < nMaxLine);
	}
	else
	{
		if (!bThin)
		{
			color = (nState == DOWN) ? GetColor(COLOR_3DSHADOW, crBkgnd) : 
					(nState == HOT) ? GetColor(COLOR_3DFACE, crBkgnd) : crBkgnd;

			pDC->FillSolidRect(rHLine, color);
			pDC->FillSolidRect(rVLine, color);
			rHLine.OffsetRect(0, 1);
			rVLine.OffsetRect(1, 0);

			if (!nRadius)
			{
				// shorten by one pixel
				rHLine.DeflateRect(1, 0);
				rVLine.DeflateRect(0, 1);
			}
			
			color = (nState == DOWN) ? GetColor(COLOR_3DDKSHADOW, crBkgnd) : 
					(nState == HOT) ? GetColor(COLOR_3DHILIGHT, crBkgnd) : crBkgnd;
		}
		else
		{
			color = (nState == DOWN) ? GetColor(COLOR_3DSHADOW, crBkgnd) : 
					(nState == HOT) ? GetColor(COLOR_3DHILIGHT, crBkgnd) : crBkgnd;
		}

		pDC->FillSolidRect(rHLine, color);
		pDC->FillSolidRect(rVLine, color);
	}
	
	// bottom
	rHLine.SetRect(rect.left + (bBottomLeft ? nRadius : 0), rect.bottom, 
					rect.right - ((bBottomRight && nRadius) ? nRadius : -1), rect.bottom + 1);
	
	// right
	rVLine.SetRect(rect.right, rect.top + (bTopRight ? nRadius : 0), 
					rect.right + 1, rect.bottom - ((bBottomRight && nRadius) ? nRadius : -1));
	
	if (bRender && crBkgnd != -1)
	{
		int nLine = 0;
		int nMaxLine = nRadius ? min(NUMFACTORS, nRadius) : 
								min(NUMFACTORS, min(rect.Width(), rect.Height()) / 2);

		do
		{
			int nFactor = (nLine * NUMFACTORS) / nMaxLine;

			COLORREF color = (nState == DOWN) ? Lighter(crBkgnd, fHiliteFactor[nFactor]) : 
							(nState == HOT) ? Darker(crBkgnd, fShadowFactor[nFactor]) : crBkgnd;

			pDC->FillSolidRect(rHLine, color);
			pDC->FillSolidRect(rVLine, color);
			rHLine.OffsetRect(0, -1);
			rVLine.OffsetRect(-1, 0);

			if (!nRadius)
			{
				// shorten by one pixel
				rHLine.DeflateRect(1, 0);
				rVLine.DeflateRect(0, 1);
			}

			nLine++;
		}
		while (nLine < nMaxLine);
	}
	else
	{
		if (!bThin)
		{
			color = (nState == DOWN) ? GetColor(COLOR_3DHILIGHT, crBkgnd) : 
					(nState == HOT) ? GetColor(COLOR_3DDKSHADOW, crBkgnd) : crBkgnd;

			pDC->FillSolidRect(rHLine, color);
			pDC->FillSolidRect(rVLine, color);
			rHLine.OffsetRect(0, -1);
			rVLine.OffsetRect(-1, 0);

			if (!nRadius)
			{
				// shorten by one pixel
				rHLine.DeflateRect(1, 0); 
				rVLine.DeflateRect(0, 1);
			}
			
			color = (nState == DOWN) ? GetColor(COLOR_3DFACE, crBkgnd) : 
					(nState == HOT) ? GetColor(COLOR_3DSHADOW, crBkgnd) : crBkgnd;
		}
		else
		{
			color = (nState == DOWN) ? GetColor(COLOR_3DHIGHLIGHT, crBkgnd) : 
					(nState == HOT) ? GetColor(COLOR_3DSHADOW, crBkgnd) : crBkgnd;
		}

		pDC->FillSolidRect(rHLine, color);
		pDC->FillSolidRect(rVLine, color);
	}
}

COLORREF CRoundCorner::GetColor(int nAngle, int nDegreesFrom, int nDegreesTo, COLORREF crFrom, COLORREF crTo)
{
	if (crFrom == crTo)
		return crFrom;

	COLORREF crResult = RGB(0, 0, 0);

	if (nDegreesFrom > nDegreesTo)
		nDegreesTo += 360;

	ASSERT (nAngle >= nDegreesFrom && nAngle <= nDegreesTo);

	if (nAngle >= nDegreesFrom && nAngle <= nDegreesTo)
	{
		// all this does is to approximate the averageof the two colors
		// at the point being queried
		BYTE byRedFrom = GetRValue(crFrom);
		BYTE byGreenFrom = GetGValue(crFrom);
		BYTE byBlueFrom = GetBValue(crFrom);
		BYTE byRedTo = GetRValue(crTo);
		BYTE byGreenTo = GetGValue(crTo);
		BYTE byBlueTo = GetBValue(crTo);

		int nOffset = nAngle - nDegreesFrom;
		int nDiff = nDegreesTo - nDegreesFrom;

		BYTE byRedResult = (byRedFrom * (nDiff - nOffset) + byRedTo * nOffset) / nDiff;
		BYTE byGreenResult = (byGreenFrom * (nDiff - nOffset) + byGreenTo * nOffset) / nDiff;
		BYTE byBlueResult = (byBlueFrom * (nDiff - nOffset) + byBlueTo * nOffset) / nDiff;

		crResult = RGB(byRedResult, byGreenResult, byBlueResult);
	}

	return crResult;
}

void CRoundCorner::DrawTopLeft(CDC* pDC, LPRECT pRect, int nRadius, DWORD dwStyle, COLORREF crBkgnd)
{
	if (!nRadius)
		return;

	BOOL bRender = (dwStyle & RC_RENDER) && (crBkgnd != -1);
	BOOL bThin = !bRender && (dwStyle & RC_THIN);

	int nState = (dwStyle & RC_DOWN) ? DOWN : (dwStyle & RC_UP) ? HOT : COLD;

	Corner cnr;

	cnr.ptQuadrant = CPoint(-1, 1);
	cnr.ptOriginOffset = CPoint(pRect->left + nRadius, pRect->top + nRadius);
	cnr.nAngleFrom = 270;
	cnr.nAngleTo = 360;

	if (bRender)
	{
		int nLine = 0;
		int nMaxLine = min(NUMFACTORS, nRadius);

		cnr.bInfillBetween = TRUE;

		do
		{
			int nFactor = (nLine * NUMFACTORS) / nMaxLine;

			cnr.crFrom = (nState == DOWN) ? Darker(crBkgnd, fShadowFactor[nFactor]) : 
							(nState == HOT) ? Lighter(crBkgnd, fHiliteFactor[nFactor]) : crBkgnd;

			cnr.crTo = cnr.crFrom;

			DrawCorner(pDC, nRadius, &cnr);
			nRadius--;
			nLine++;
		}
		while (nLine < nMaxLine);
	}
	else
	{
		if (!bThin)
		{
			cnr.crFrom = (nState == DOWN) ? GetColor(COLOR_3DSHADOW, crBkgnd) : 
							(nState == HOT) ? GetColor(COLOR_3DFACE, crBkgnd) : crBkgnd;

			cnr.crTo = cnr.crFrom;

			cnr.bInfillBetween = TRUE;
			DrawCorner(pDC, nRadius, &cnr);
			nRadius--;

			cnr.crFrom = (nState == DOWN) ? GetColor(COLOR_3DDKSHADOW, crBkgnd) : 
							(nState == HOT) ? GetColor(COLOR_3DHILIGHT, crBkgnd) : crBkgnd;
		}
		else
		{
			cnr.crFrom = (nState == DOWN) ? GetColor(COLOR_3DSHADOW, crBkgnd) : 
							(nState == HOT) ? GetColor(COLOR_3DHILIGHT, crBkgnd) : crBkgnd;
		}

		cnr.crTo = cnr.crFrom;

		cnr.bInfillBetween = FALSE;
		DrawCorner(pDC, nRadius, &cnr);
	}
}

void CRoundCorner::DrawTopRight(CDC* pDC, LPRECT pRect, int nRadius, DWORD dwStyle, COLORREF crBkgnd)
{
	if (!nRadius)
		return;

	BOOL bRender = (dwStyle & RC_RENDER) && (crBkgnd != -1);
	BOOL bThin = !bRender && (dwStyle & RC_THIN);

	int nState = (dwStyle & RC_DOWN) ? DOWN : (dwStyle & RC_UP) ? HOT : COLD;

	Corner cnr;

	cnr.ptQuadrant = CPoint(1, 1);
	cnr.ptOriginOffset = CPoint(pRect->right - nRadius, pRect->top + nRadius);
	cnr.nAngleFrom = 0;
	cnr.nAngleTo = 90;

	if (bRender)
	{
		int nLine = 0;
		int nMaxLine = min(NUMFACTORS, nRadius);

		cnr.bInfillBetween = TRUE;

		do
		{
			int nFactor = (nLine * NUMFACTORS) / nMaxLine;

			cnr.crFrom = (nState == DOWN) ? Darker(crBkgnd, fShadowFactor[nFactor]) : 
							(nState == HOT) ? Lighter(crBkgnd, fHiliteFactor[nFactor]) : crBkgnd;

			cnr.crTo = (nState == DOWN) ? Lighter(crBkgnd, fHiliteFactor[nFactor]) : 
							(nState == HOT) ? Darker(crBkgnd, fShadowFactor[nFactor]) : crBkgnd;

			DrawCorner(pDC, nRadius, &cnr);
			nRadius--;
			nLine++;
		}
		while (nLine < nMaxLine);
	}
	else
	{
		if (!bThin)
		{
			cnr.crFrom = (nState == DOWN) ? GetColor(COLOR_3DSHADOW, crBkgnd) : 
							(nState == HOT) ? GetColor(COLOR_3DFACE, crBkgnd) : crBkgnd;

			cnr.crTo = (nState == DOWN) ? GetColor(COLOR_3DFACE, crBkgnd) : 
							(nState == HOT) ? GetColor(COLOR_3DSHADOW, crBkgnd) : crBkgnd;

			cnr.bInfillBetween = TRUE;
			DrawCorner(pDC, nRadius, &cnr);
			nRadius--;

			cnr.crFrom = (nState == DOWN) ? GetColor(COLOR_3DDKSHADOW, crBkgnd) : 
							(nState == HOT) ? GetColor(COLOR_3DHILIGHT, crBkgnd) : crBkgnd;

			cnr.crTo = (nState == DOWN) ? GetColor(COLOR_3DHILIGHT, crBkgnd) : 
							(nState == HOT) ? GetColor(COLOR_3DDKSHADOW, crBkgnd) : crBkgnd;
		}
		else
		{
			cnr.crFrom = (nState == DOWN) ? GetColor(COLOR_3DSHADOW, crBkgnd) : 
							(nState == HOT) ? GetColor(COLOR_3DHILIGHT, crBkgnd) : crBkgnd;

			cnr.crTo = (nState == DOWN) ? GetColor(COLOR_3DHILIGHT, crBkgnd) : 
							(nState == HOT) ? GetColor(COLOR_3DSHADOW, crBkgnd) : crBkgnd;
		}

		cnr.bInfillBetween = FALSE;
		DrawCorner(pDC, nRadius, &cnr);
	}
}

void CRoundCorner::DrawBottomLeft(CDC* pDC, LPRECT pRect, int nRadius, DWORD dwStyle, COLORREF crBkgnd)
{
	if (!nRadius)
		return;

	BOOL bRender = (dwStyle & RC_RENDER) && (crBkgnd != -1);
	BOOL bThin = !bRender && (dwStyle & RC_THIN);

	int nState = (dwStyle & RC_DOWN) ? DOWN : (dwStyle & RC_UP) ? HOT : COLD;

	Corner cnr;

	cnr.ptQuadrant = CPoint(-1, -1);
	cnr.ptOriginOffset = CPoint(pRect->left + nRadius, pRect->bottom - nRadius);
	cnr.nAngleFrom = 180;
	cnr.nAngleTo = 270;

	if (bRender)
	{
		int nLine = 0;
		int nMaxLine = min(NUMFACTORS, nRadius);

		cnr.bInfillBetween = TRUE;

		do
		{
			int nFactor = (nLine * NUMFACTORS) / nMaxLine;

			cnr.crFrom = (nState == DOWN) ? Lighter(crBkgnd, fHiliteFactor[nFactor]) : 
							(nState == HOT) ? Darker(crBkgnd, fShadowFactor[nFactor]) : crBkgnd;

			cnr.crTo = (nState == DOWN) ? Darker(crBkgnd, fShadowFactor[nFactor]) : 
							(nState == HOT) ? Lighter(crBkgnd, fHiliteFactor[nFactor]) : crBkgnd;

			DrawCorner(pDC, nRadius, &cnr);
			nRadius--;
			nLine++;
		}
		while (nLine < nMaxLine);
	}
	else
	{
		if (!bThin)
		{
			cnr.crFrom = (nState == DOWN) ? GetColor(COLOR_3DHILIGHT, crBkgnd) : 
							(nState == HOT) ? GetColor(COLOR_3DDKSHADOW, crBkgnd) : crBkgnd;

			cnr.crTo = (nState == DOWN) ? GetColor(COLOR_3DSHADOW, crBkgnd) : 
							(nState == HOT) ? GetColor(COLOR_3DFACE, crBkgnd) : crBkgnd;

			cnr.bInfillBetween = TRUE;
			DrawCorner(pDC, nRadius, &cnr);
			nRadius--;

			cnr.crFrom = (nState == DOWN) ? GetColor(COLOR_3DFACE, crBkgnd) : 
							(nState == HOT) ? GetColor(COLOR_3DSHADOW, crBkgnd) : crBkgnd;

			cnr.crTo = (nState == DOWN) ? GetColor(COLOR_3DDKSHADOW, crBkgnd) : 
							(nState == HOT) ? GetColor(COLOR_3DHILIGHT, crBkgnd) : crBkgnd;
		}
		else
		{
			cnr.crFrom = (nState == DOWN) ? GetColor(COLOR_3DHIGHLIGHT, crBkgnd) : 
							(nState == HOT) ? GetColor(COLOR_3DSHADOW, crBkgnd) : crBkgnd;

			cnr.crTo = (nState == DOWN) ? GetColor(COLOR_3DSHADOW, crBkgnd) : 
							(nState == HOT) ? GetColor(COLOR_3DHILIGHT, crBkgnd) : crBkgnd;
		}

		cnr.bInfillBetween = FALSE;
		DrawCorner(pDC, nRadius, &cnr);
	}
}

void CRoundCorner::DrawBottomRight(CDC* pDC, LPRECT pRect, int nRadius, DWORD dwStyle, COLORREF crBkgnd)
{
	if (!nRadius)
		return;

	BOOL bRender = (dwStyle & RC_RENDER) && (crBkgnd != -1);
	BOOL bThin = !bRender && (dwStyle & RC_THIN);

	int nState = (dwStyle & RC_DOWN) ? DOWN : (dwStyle & RC_UP) ? HOT : COLD;

	Corner cnr;

	cnr.ptQuadrant = CPoint(1, -1);
	cnr.ptOriginOffset = CPoint(pRect->right - nRadius, pRect->bottom - nRadius);
	cnr.nAngleFrom = 90;
	cnr.nAngleTo = 180;

	if (bRender)
	{
		int nLine = 0;
		int nMaxLine = min(NUMFACTORS, nRadius);

		cnr.bInfillBetween = TRUE;

		do
		{
			int nFactor = (nLine * NUMFACTORS) / nMaxLine;

			cnr.crFrom = (nState == DOWN) ? Lighter(crBkgnd, fHiliteFactor[nFactor]) : 
							(nState == HOT) ? Darker(crBkgnd, fShadowFactor[nFactor]) : crBkgnd;

			cnr.crTo = cnr.crFrom;

			DrawCorner(pDC, nRadius, &cnr);
			nRadius--;
			nLine++;
		}
		while (nLine < nMaxLine);
	}
	else
	{
		if (!bThin)
		{
			cnr.crFrom = (nState == DOWN) ? GetColor(COLOR_3DHILIGHT, crBkgnd) : 
							(nState == HOT) ? GetColor(COLOR_3DDKSHADOW, crBkgnd) : crBkgnd;

			cnr.crTo = cnr.crFrom;

			cnr.bInfillBetween = TRUE;
			DrawCorner(pDC, nRadius, &cnr);
			nRadius--;

			cnr.crFrom = (nState == DOWN) ? GetColor(COLOR_3DFACE, crBkgnd) : 
							(nState == HOT) ? GetColor(COLOR_3DSHADOW, crBkgnd) : crBkgnd;
		}
		else
		{
			cnr.crFrom = (nState == DOWN) ? GetColor(COLOR_3DHIGHLIGHT, crBkgnd) : 
							(nState == HOT) ? GetColor(COLOR_3DSHADOW, crBkgnd) : crBkgnd;
		}

		cnr.crTo = cnr.crFrom;

		cnr.bInfillBetween = FALSE;
		DrawCorner(pDC, nRadius, &cnr);
	}
}

void CRoundCorner::DrawCorner(CDC* pDC, int nRadius, Corner* pCorner)
{
	CPoint ptBase(0, nRadius);
	int nDecision = 1 - nRadius;

	while (ptBase.y >= ptBase.x)
	{
		// translate to target quadrant
		CPoint ptQuadrant(ptBase.x * pCorner->ptQuadrant.x, ptBase.y * pCorner->ptQuadrant.y);

		// flip to adjacent octant
		int nFlip = ((pCorner->ptQuadrant.x > 0 && pCorner->ptQuadrant.y > 0) ||
					(pCorner->ptQuadrant.x < 0 && pCorner->ptQuadrant.y < 0)) ? 1 : -1;
		
		CPoint ptOctant(ptQuadrant.y * nFlip, ptQuadrant.x * nFlip);

		// adjust y value for MM_TEXT
		ptQuadrant.y = -ptQuadrant.y;
		ptOctant.y = -ptOctant.y;

		// offset to actual position
		ptQuadrant.Offset(pCorner->ptOriginOffset);
		ptOctant.Offset(pCorner->ptOriginOffset);

		// draw pixels
		double dRad = asin((double)ptBase.x / nRadius);
		int nAngle = (int)((dRad * 180) / Pi);

		COLORREF crQuadrant = GetColor(pCorner->nAngleFrom + nAngle, 
									pCorner->nAngleFrom, 
									pCorner->nAngleTo, 
									pCorner->crFrom, 
									pCorner->crTo);

		pDC->SetPixelV(ptQuadrant, crQuadrant);

		COLORREF crOctant = GetColor(pCorner->nAngleTo - nAngle, 
									pCorner->nAngleFrom, 
									pCorner->nAngleTo, 
									pCorner->crFrom, 
									pCorner->crTo);

		pDC->SetPixelV(ptOctant, crOctant);

		// next iteration
		if (nDecision < 0)
		{
			nDecision += (2 * ptBase.x + 3);
			ptBase.x++;
		}
		else
		{
			nDecision += (2 * (ptBase.x - ptBase.y) + 5);
			ptBase.y--;
			ptBase.x++;

			if (pCorner->bInfillBetween)
			{
				// draw fill in pixel
				ptQuadrant.y += pCorner->ptQuadrant.y;
				ptOctant.x -= pCorner->ptQuadrant.x;

				// draw pixels
				pDC->SetPixelV(ptQuadrant, crQuadrant);
				pDC->SetPixelV(ptOctant, crOctant);
			}
		}
	}
}

//////////////////////////////////

COLORREF CRoundCorner::GetColor(int nColor, COLORREF crBase)
{
	if (crBase != -1)
	{
		switch (nColor)
		{
		case COLOR_3DHILIGHT:
			return Lighter(crBase);
			
		case COLOR_3DSHADOW:	
			return Darker(crBase, 0.75f);
			
		case COLOR_3DDKSHADOW:	
			return Darker(crBase, 0.2f);

		case COLOR_3DFACE:	
//		case COLOR_PARENTBKGND:
			return crBase;
		}
	}

	// default
	if (nColor == COLOR_PARENTBKGND)
		nColor = COLOR_3DFACE;

	return ::GetSysColor(nColor);
}

COLORREF CRoundCorner::Darker(COLORREF crBase, float fFactor)
{
	if (fFactor <= 0.0f)
		return 0;

	else if (fFactor >= 1.0f)
		return crBase;

	fFactor = min(fFactor, 1.0f);
	fFactor = max(fFactor, 0.0f);

	BYTE bRed, bBlue, bGreen;
	BYTE bRedShadow, bBlueShadow, bGreenShadow;

	bRed = GetRValue(crBase);
	bBlue = GetBValue(crBase);
	bGreen = GetGValue(crBase);

	bRedShadow = (BYTE)(bRed * fFactor) + (bRed % 2);
	bBlueShadow = (BYTE)(bBlue * fFactor) + (bBlue % 2);
	bGreenShadow = (BYTE)(bGreen * fFactor) + (bGreen % 2);

	return RGB(bRedShadow, bGreenShadow, bBlueShadow);
}

COLORREF CRoundCorner::Lighter(COLORREF crBase, float fFactor) 
{
	if (fFactor <= 0.0f)
		return crBase;

	else if (fFactor >= 1.0f)
		return RGB(255, 255, 255);

	fFactor = min(fFactor, 1.0f);
	fFactor = max(fFactor, 0.0f);

	BYTE bRed, bBlue, bGreen;
	BYTE bRedHilite, bBlueHilite, bGreenHilite;

	bRed = GetRValue(crBase);
	bBlue = GetBValue(crBase);
	bGreen = GetGValue(crBase);

	bRedHilite = min(255, bRed + (BYTE)(255 * fFactor));
	bBlueHilite = min(255, bBlue + (BYTE)(255 * fFactor));
	bGreenHilite = min(255, bGreen + (BYTE)(255 * fFactor));

	return RGB(bRedHilite, bGreenHilite, bBlueHilite);
}